home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Trading on the Edge
/
Trading On The Edge - CD-ROM Toolkit (Wayzata Technology)(2031)(1994).bin
/
pc
/
mac_file
/
vendor_d
/
neuralwa
/
nw2v50
/
usermstd.c
< prev
next >
Wrap
Text File
|
1993-08-23
|
18KB
|
634 lines
/* $Id$ */
/* $Log$ */
/* 12-24-90 (usermath.c) User-Defined Neuro-Dynamics Prototype */
/************************************************************************
* Copyright(C) 1987-1992 NeuralWare Inc *
* Penn Center West, IV-227, Pittsburgh, PA 15276 *
* Telephone: (412) 787-8222 FAX: (412) 787-8220 *
* *
* All rights reserved. No part of this program may be reproduced, *
* stored in a retrieval system, or transmitted, in any form or by any *
* means, electronic, mechanical, photocopying, recording or otherwise *
* without the prior written permission of the copyright owner, *
* NeuralWare, Inc. *
* *
* PROPRIETARY NOTICE *
* *
* This document is the property of NeuralWare, Inc. and contains *
* trade-secrets and other proprietary information. The information *
* herein is reserved as proprietary to NeuralWare, and is not to be *
* published, reproduced, copied, disclosed, used, or reverse *
* engineered without the express written consent of a duly authorized *
* representative of NeuralWare. *
************************************************************************
*/
#define USERMATH
#include <math.h>
#ifdef DPTEST
#include "nn_run.h"
#else
#include "usermath.h"
#endif
#ifndef DPTEST
#define USER_BACKPROP 1
#undef USER_BACKPROP
/* Useful preprocessor macros */
/* (a) Recall Schedule Macros: */
#define RCOLP (ulp->r_col_p) /* Recall column pointer */
#define RCOLX (ulp->r_col_x) /* Recall column index */
#define RSTEP (RCOLP->rstep)
#define CLAMP (RCOLP->iclamp)
#define FIRE (RCOLP->fire)
#define RTEMP (RCOLP->rtemp)
#define MODF (RCOLP->modf)
#define GAIN (RCOLP->gain)
#define RCOEF5 (RCOLP->rcoef[0])
#define RCOEF6 (RCOLP->rcoef[1])
#define RCOEF7 (RCOLP->rcoef[2])
#define RCOEF8 (RCOLP->rcoef[3])
#define RCOEF9 (RCOLP->rcoef[4])
/* (b) Learn Schedule Macros: */
#define LCOLP (ulp->l_col_p) /* Learn column pointer */
#define LCOLX (ulp->l_col_x) /* Learn column index */
#define LSTEP (LCOLP->lcount)
#define LTEMP (LCOLP->ltemp)
#define LCOEF1 (LCOLP->lcoef1)
#define LCOEF2 (LCOLP->lcoef2)
#define LCOEF3 (LCOLP->lcoef3)
#define LCOEF4 (LCOLP->lcoef[0])
#define LCOEF5 (LCOLP->lcoef[1])
#define LCOEF6 (LCOLP->lcoef[2])
#define LCOEF7 (LCOLP->lcoef[3])
#define LCOEF8 (LCOLP->lcoef[4])
#define LCOEF9 (LCOLP->lcoef[5])
/* (c) Network Counter Macros: */
#define RCOUNT (um_ctr[CTR_RECALL])
#define LAYERN (um_ctr[CTR_LAYER])
#define LCOUNT (um_ctr[CTR_LEARN])
#define AUX1 (um_ctr[CTR_AUX1])
#define AUX2 (um_ctr[CTR_AUX2])
#define AUX3 (um_ctr[CTR_AUX3])
#define WORK1 (um_ctr[CTR_WRK1])
#define WORK2 (um_ctr[CTR_WRK2])
/* (d) Layer Parameter macros: */
#define SCALE (ulp->scale)
#define OFFST (ulp->offset)
#define LO_CLIP (ulp->lo_clip)
#define HI_CLIP (ulp->hi_clip)
#define FP_OFF (ulp->fprime_off)
#define EXPLIM 12.0 /* limit for exponentials to be fixed */
#endif /* DPTEST */
#ifndef DPK
/* um_event() is called whenever a significant event occurs which might
require attention by this particular usermath routine. It is ONLY
called if the current network uses a user-math function in one of
its layers. */
#if defined(ANSI_HEADER)
NINT um_event( XB *netnp, XB *csnp, USR_LYR *SLayerp, NINT code )
#else
NINT um_event( netnp, csnp, SLayerp, code )
XB *netnp; /* network name (ascii) */
XB *csnp; /* control strategy name pointer */
USR_LYR *SLayerp; /* current super-layer pointer */
NINT code; /* event code */
#endif
{
NINT rc; /* return code */
rc = 0;
#ifndef DPTEST
switch( code ) {
case UME_LSTART: /* start of learning */
rc = 1; break;
case UME_LEND: /* end of learning */
rc = 2; break;
case UME_TSTART: /* start of recall test */
rc = 3; break;
case UME_RSTART: /* start of recall */
rc = 4; break;
case UME_REND: /* end of recall */
rc = 5; break;
case UME_LOAD: /* network has been loaded */
rc = 6; break;
case UME_SAVE: /* network is about to be saved */
rc = 7; break;
case UME_DELETE: /* network is about to be deleted */
rc = 8; break;
default:
rc = 9; break;
}
#endif /* DPTEST */
return( rc );
}
/* um_chkpt is called when User check-pointing is active in the NWorks
Run/CheckPoints dialog box. um_chkpt( ) is called at the requested
checkpoints for each PE in each layer with a User Math function. */
#if defined(ANSI_HEADER)
NINT um_chkpt( USR_PE *upep, USR_CN_HDR *uchp, USR_LYR *ulp)
#else
NINT um_chkpt( upep, uchp, ulp )
USR_PE *upep; /* Pointer to current PE */
USR_CN_HDR *uchp; /* Pointer to connection header */
USR_LYR *ulp;
#endif
{
NINT rc; /* return code */
rc = 0;
return( rc );
}
#endif /* DPK */
#ifndef DPTEST
#ifndef DPK
/**/
/* The um_s_user routines are called if the "sum" bit of the math microcode
is set and a user summation function is selected in the summation
scroll window of the layer dialog box */
#ifdef USER_BACKPROP
/* bkpstdSum */
#if defined(ANSI_HEADER)
NINT um_s_backprop( USR_PE *upep, USR_CN_HDR *uchp, USR_LYR *ulp)
#else
NINT um_s_backprop(upep, uchp, ulp)
USR_PE *upep; /* Pointer to current PE */
USR_CN_HDR *uchp; /* Pointer to connection header */
USR_LYR *ulp;
#endif
{
USR_CONN *ct; /* Connection Table */
NINT wx, wf;
REAL wv, accum;
NINT sizewts;
if ( IS_INIT )
return (0);
if ( IS_PRE_POST )
return 0;
accum = 0.0;
sizewts = ulp->functions.size_wts;
for ( wx = 0, ct = &uchp->conn_table[0];
wx < uchp->num_conns; wx++, UPDWXP(ct,sizewts) ) {
wf = ct->flag;
wv = ct->weight;
if ( (wf & CN_DISABLED) != 0 ) continue;
wf &= CN_WT_MASK;
if ( wf == CN_SET ) wv *= CLAMP;
else if ( wf == CN_MOD ) wv *= MODF;
accum += ( ct->src_pe->out_val * wv);
}
upep->sum_val = accum;
return(0);
}
#endif
/**/
/***********************************************************************
*
* User Transform routines
*
***********************************************************************
*/
/* The um_t_user routines are called in any of three cases :
> an INIT button is selected, which sets the UMCF_INIT flag
> the "e*=f'" bit is selected, which sets the UMCF_DERIV flag
> if the "tran" bit of the math microcode is set and a user transfer
function is selected in the current layer. ( neither UMCF_INIT
nor UMCF_DERIV will be set )
*/
#ifdef USER_BACKPROP
#if defined(ANSI_HEADER)
NINT um_t_backprop( USR_PE *upep, USR_CN_HDR *uchp, USR_LYR *ulp)
#else
NINT um_t_backprop(upep, uchp, ulp)
USR_PE *upep; /* Pointer to current PE */
USR_CN_HDR *uchp; /* Pointer to connection header */
USR_LYR *ulp; /* Pointer to current layer */
#endif
{
REAL wr; /* work real */
REAL rv; /* random value */
if ( IS_INIT )
return (0);
if ( IS_PRE_POST )
return (0);
if ( IS_DERIV ) {
if ( fabs( SCALE ) < NRZRO ) {
upep->err_val = 0.0;
} else {
upep->err_val /= SCALE; /* remove scaling from error */
/* Strip off scale and offset from tran value */
wr = ( upep->trn_val - OFFST ) / SCALE;
wr = wr * (1.0-wr) * GAIN;
wr += FP_OFF;
upep->err_val *= wr;
}
}
else /* not DERIV */ {
wr = upep->sum_val * GAIN; /* value to work with */
rv = 0.0;
if ( (um_micro & MF_LNOISE) != 0 ) rv += LTEMP;
if ( (um_micro & MF_RNOISE) != 0 ) rv += RTEMP;
if ( rv > 0.0 ) {
rv = 0.02 * rv; /* scale to 2 * percentage */
wr += rv * ( nrand( ) * RANDINV - 0.5 ); /* add noise */
}
if ( wr > EXPLIM ) wr = 1.0;
else if ( wr < -EXPLIM ) wr = 0.0;
else wr = 1.0 / ( 1.0 + exp( -wr ) );
/* Offset, scale and hard limit */
upep->trn_val = SCALE * wr + OFFST;
if ( upep->trn_val < LO_CLIP ) upep->trn_val = LO_CLIP;
if ( upep->trn_val > HI_CLIP ) upep->trn_val = HI_CLIP;
}
return (0);
}
#endif
/***********************************************************************
*
* User Defined Output Functions
*
***********************************************************************
*/
/* The um_o_user routines are called if the "output" bit of the math microcode
is set and a user output function is selected in the output function
scroll window of the layer dialog box */
/***********************************************************
*
* This is here for compatibility with prevoius versions of PNN
*
***********************************************************
*/
#if defined(ANSI_HEADER)
NINT um_o_pnn( USR_PE *upep, USR_CN_HDR *uchp, USR_LYR *ulp)
#else
NINT um_o_pnn(upep, uchp, ulp)
USR_PE *upep; /* Pointer to current PE */
USR_CN_HDR *uchp; /* Pointer to connection header */
USR_LYR *ulp; /* Pointer to current layer */
#endif
{
LOCAL found;
if ( IS_INIT )
return (0);
if ( IS_PRELYR ) found = 0; /* Start of lyr */
if ( IS_PRE_POST ) return (0);
if ( upep->flag&PE_NOT_LEARNED ) { /* Not yet lrned */
upep->out_val = 0.0; /* Zero output */
/* If learn PE not yet found, see if this is the one */
if ( !found && upep->err_val > NRZRO ) {
ulp->pe_kcur = upep; /* This PE lrns */
found = 1; /* Stop looking */
}
} else {
upep->out_val = upep->trn_val; /* Direct output */
}
return ( 0 );
}
/***********************************************************************
*
* User Defined Error Functions
*
***********************************************************************
*/
/* The um_e_user routines are called if the "e-=w" bit of the math microcode
is set and an error function is selected in the error function
scroll window of the layer dialog box */
#ifdef USER_BACKPROP
#if defined(ANSI_HEADER)
NINT um_e_backprop( USR_PE *upep, USR_CN_HDR *uchp, USR_LYR *ulp)
#else
NINT um_e_backprop(upep, uchp, ulp)
USR_PE *upep; /* Pointer to current PE */
USR_CN_HDR *uchp; /* Pointer to connection header */
USR_LYR *ulp; /* Pointer to current layer */
#endif
{
if ( IS_INIT )
return (0);
if ( IS_PRE_POST ) return ( 0 );
upep->err_val = upep->err_val - upep->trn_val;
/* check for apriori error modifications */
if ( (um_micro & MF_ERRFAC) != 0 )
upep->err_val *= upep->err_fac;
/* special variant of back-propagation */
if( fabs( upep->err_val ) < LCOEF3 )
upep->err_val = 0.0;
return (0);
}
#endif
/***********************************************************************
*
* User Defined Learn Functions
*
***********************************************************************
*/
/* The um_l_user routines are called if the "learn" bit of the math microcode
is set and a user learn function is selected in the learn function
scroll window of the layer dialog box */
/***********************************************************
* This has been kept in for compatibility reasons to
* support old versions of PNN.
*
* This is a general Kohonen type learning where it is
* assumed that the output function has set the pe_kcur
* field of ulp to point to the PE which should learn.
* When um_flag has its UMCF_POSTLYR bit set, upep is set
* to ulp->pe_kcur and uchp is set to the connection
* header for upep. Consequently this section of code
* need only be entered when the UCMF_POSTLYR bit is set.
* It is required that the output and learn functions
* appear on the same control strategy math instruction
* line.
***********************************************************
*/
#if defined(ANSI_HEADER)
NINT um_l_kohonen( USR_PE *upep, USR_CN_HDR *uchp, USR_LYR *ulp)
#else
NINT um_l_kohonen(upep, uchp, ulp)
USR_PE *upep; /* Pointer to current PE */
USR_CN_HDR *uchp; /* Pointer to connection header */
USR_LYR *ulp; /* Pointer to current layer */
#endif
{
REAL lcoef, wv;
NINT wx;
USR_CONN *ct; /* Connection Table */
REAL ssw; /* Sum of squared weights */
REAL issw; /* Inverse sum of squared weights */
NINT sizewts;
if (ulp)
sizewts = ulp->functions.size_wts;
if ( IS_INIT ) {
if ( IS_PRE_POST ) return (0);
upep->flag |= PE_NOT_LEARNED;
/* sum squared weights of variable connections entering PE */
ssw = 0.0;
for ( wx = 0, ct = &uchp->conn_table[0];
wx < (NINT)uchp->num_conns; wx++, UPDWXP(ct,sizewts) ) {
if ( (ct->flag & (CN_DISABLED|CN_WT_MASK)) != CN_VAR )
continue; /* Not a variable weight */
ct->flag &= ~CN_USER; /* Initialize User Flag */
ssw += ct->weight * ct->weight; /* Sum squared weights */
ct->last_dw = 0.0; /* Zero out Delta Weight */
}
if ( ssw > NRZRO ) {
issw = 1.0 / sqrt( ssw );
/* Normalize the enabled variable weights to length 1.0 */
for ( wx = 0, ct = &uchp->conn_table[0];
wx < (NINT)uchp->num_conns; wx++, UPDWXP(ct,sizewts) ) {
if ( (ct->flag & (CN_DISABLED|CN_WT_MASK)) != CN_VAR )
continue; /* Not a variable weight */
ct->weight = issw * ct->weight;
}
}
}
else { /* not INIT */
if ( IS_POSTLYR ) {
if ( upep == (USR_PE *)0 )
return ( 0 );
/* Calculate learning coefficient */
lcoef = LCOEF1;
if ( lcoef < NRZRO )
return ( 0 );
if ( upep->flag & PE_NOT_LEARNED )
lcoef = 1.0; /* fast initial learning */
/* dW = alpha * ( W - Input ) */
for ( wx = 0, ct = &uchp->conn_table[0];
wx < (NINT)uchp->num_conns;
wx++, UPDWXP(ct,sizewts) ) {
if ( (ct->flag & (CN_DISABLED|CN_WT_MASK)) != CN_VAR )
continue; /* Not a variable weight */
/* compute the weight change */
wv = lcoef * ( ct->src_pe->out_val - ct->weight );
/* change the weights */
ct->last_dw = wv;
ct->weight += wv;
}
upep->flag &= ~PE_NOT_LEARNED; /* PE has learned */
}
}
return ( 0 );
}
#ifdef USER_BACKPROP
#if defined(ANSI_HEADER)
NINT um_l_backprop( USR_PE *upep, USR_CN_HDR *uchp, USR_LYR *ulp)
#else
NINT um_l_backprop(upep, uchp, ulp)
USR_PE *upep; /* Pointer to current PE */
USR_CN_HDR *uchp; /* Pointer to connection header */
USR_LYR *ulp; /* Pointer to current layer */
#endif
{
REAL lcoef, wv;
NINT wx;
USR_CONN *ct; /* Connection Table */
NINT sizewts;
if ( IS_INIT )
return (0);
if ( IS_PRE_POST ) return ( 0 );
lcoef = LCOEF1 * upep->err_val;
sizewts = ulp->functions.size_wts;
for ( wx = 0, ct = &uchp->conn_table[0];
wx < uchp->num_conns; wx++, UPDWXP(ct,sizewts) ) {
if ( (ct->flag & (CN_DISABLED|CN_WT_MASK)) != CN_VAR )
continue; /* Not a variable weight */
/* compute the weight change */
wv = lcoef * ct->src_pe->out_val + LCOEF2 * ct->last_dw;
ct->last_dw = wv;
ct->weight += wv;
}
return ( 0 );
}
#endif
#endif /* not DPK */
/* setup_umath is called just once as part of NeuralWorks initialization code.
It is used to bind user names and function pointers to the function
indices. */
#endif /* DPTEST */
#ifndef TRANS_PHYS
#ifndef DPTEST
GLOBALREF NINT DR_Sum, DR_Tran, DR_Compf, DR_Learn, DR_ErrF, DR_Noise;
IMPORT NINT AddUserFunction ARGLIST(( NINT *, NINT, TEXT *, TEXT *,
NINT (*)(), NINT, NINT ));
/* The arguments to AddUserFunction ( dir, index, my_name, menu_name,
FNP(fn_ptr), min_nwtflds , default_nwtflds)
are as follows :
> a pointer to one of the following "directories" -
DR_Sum, DR_Tran, DR_Compf, DR_Learn, DR_ErrF, DR_Noise -
which must not be modified in any fashion!
> index of the function
> the actual name of the function as it appears in the C code
( used to generate Designer Pack code )
> name of the function to appear on the Layer Edit menu
> actual function address, which will be bound to the layer; example
FNP(um_l_whatsit). The FNP macro is needed to work properly with Designer
Pack.
> minimum number of "weight fields" the function requires.
> default number of "weight fields" the function requires.
*/
#ifdef DPK
#define FNP(a) 0
#else
#define FNP(a) a
#endif /* not DPK */
#endif /* DPTEST */
NINT setup_umath( NO_ARGS )
{
#ifndef DPTEST
/* Sum functions */
#ifdef USER_BACKPROP
AddUserFunction(&DR_Sum, LS_USER1,
"um_s_backprop", "bkpstdSum", FNP(um_s_backprop), 1, 1);
#endif
/* Transfer functions */
#ifdef USER_BACKPROP
AddUserFunction(&DR_Tran, LT_USER3,
"um_t_backprop", "bkpstdTran", FNP(um_t_backprop), 1, 1);
#endif
/* Output functions */
AddUserFunction(&DR_Compf, LU_USER1,
"um_o_pnn", "PNN", FNP(um_o_pnn), 1, 1);
/* export Error functions */
#ifdef USER_BACKPROP
AddUserFunction(&DR_ErrF, LE_USER1,
"um_e_backprop", "bkpstderr", FNP(um_e_backprop), 1, 1);
#endif
/* Learn functions */
AddUserFunction(&DR_Learn, LL_USER1,
"um_l_kohonen", "User Kohonen", FNP(um_l_kohonen), 2, 2);
#ifdef USER_BACKPROP
AddUserFunction(&DR_Learn, LL_USER3,
"um_l_backprop", "bkpstdLrn", FNP(um_l_backprop), 2, 2);
#endif
#endif /* Not DPTEST */
return(0);
}
#endif /* not TRANS_PHYS */